package com.xxkj.drugtraceability.utils

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import android.text.TextUtils
import android.util.Log
import androidx.core.content.FileProvider
import com.xxkj.drugtraceability.App.Companion.CONTEXT
import com.xxkj.drugtraceability.net.WanService
import kotlinx.coroutines.*
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.nio.channels.FileChannel
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.collections.HashMap
import kotlin.jvm.Throws


/**
 * Created by zhoujingjin on 2020/8/17.
 * 常用的一些工具类
 * 静态方法传入Context尽量传入ApplicationContext，以免造成内存泄漏
 */
object CommonUtils {
    /**
     * 根据手机的分辨率从 dip 的单位 转成为 px(像素)
     */
    fun dip2px(context: Context, dpValue: Float): Int {
        var context = context
        context = context.applicationContext
        val scale = context.resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }


    private const val SPACE_TIME = 300 //2次点击的间隔时间，单位ms
    private var lastClickTime: Long = 0
    fun isDoubleClick(spaceTime:Int= SPACE_TIME): Boolean {
        val currentTime = System.currentTimeMillis()
        val isClick: Boolean
        isClick = currentTime - lastClickTime <= spaceTime
        lastClickTime = currentTime
        return isClick
    }

    fun getNumber(value: String?): String? {
        // 控制正则表达式的匹配行为的参数(小数)
        var str = ""
        var p = Pattern.compile("(\\d+\\.\\d+)")
        //Matcher类的构造方法也是私有的,不能随意创建,只能通过Pattern.matcher(CharSequence input)方法得到该类的实例.
        var m = p.matcher(value)
        //m.find用来判断该字符串中是否含有与"(\\d+\\.\\d+)"相匹配的子串
        if (m.find()) {
            //如果有相匹配的,则判断是否为null操作
            //group()中的参数：0表示匹配整个正则，1表示匹配第一个括号的正则,2表示匹配第二个正则,在这只有一个括号,即1和0是一样的
            str = if (m.group(1) == null) "" else m.group(1)
        } else {
            //如果匹配不到小数，就进行整数匹配
            p = Pattern.compile("(\\d+)")
            m = p.matcher(value)
            str = if (m.find()) {
                //如果有整数相匹配
                if (m.group(1) == null) "" else m.group(1)
            } else {
                //如果没有小数和整数相匹配,即字符串中没有整数和小数，就设为空
                ""
            }
        }
        return str
    }

//    fun cutDrugName(drugName: String): String {
//        var drugName = drugName
//        val cutDrugName = getName(drugName)
//        if (!TextUtils.isEmpty(cutDrugName) && cutDrugName.length > 3) {
//            drugName = cutDrugName
//        }
//        return drugName
//    }

    private fun getName(str: String): String {
        val chars = str.toCharArray()
        var result = ""
        var start = -1
        var end = -1
        var isContainsOther = false
        for (i in chars.indices) {
            val chr = chars[i]
            if (chr == '(' || chr == '（' || chr == '[') {
                if (start == -1) start = i else isContainsOther = true
            } else if (chr == ')' || chr == '）' || chr == ']') {
                if (end == -1) end = i else isContainsOther = true
            }
        }
        try {
            if (start == -1 && end == -1) result = str else if (end != -1 && (start > end || start == -1)) result = str.substring(end + 1) else if (end > start && start == 0) {
                result = str.substring(end + 1)
            } else if (end == str.length - 1) result = str.substring(0, start) else if (start != -1 && end != str.length - 1 && end > start) {
                result = str.substring(0, start) + str.substring(end + 1)
            }
            if (isContainsOther) result = getName(result)
        } catch (e: Exception) {
            e.printStackTrace()
            result = str
        }
        if (TextUtils.isEmpty(result)) result = str
        return result
    }

    fun getTime(str: String): String {
        var result = ""
        if (str.isNullOrEmpty()) {
            return result
        } else {
            if (str.length > 16) {
                result = str.substring(0, 16)
            }
        }
        return result
    }

    /**
     * 获取版本号名称
     *
     * @param context 上下文
     * @return
     */
    fun getVerName(context: Context): String? {
        var verName: String? = ""
        try {
            verName = context.packageManager.getPackageInfo(context.packageName, 0).versionName
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return verName
    }

    /**
     * 获取手机系统版本
     */
    fun getVersion(): String? {
        return "Android" + Build.VERSION.RELEASE
    }

    /**
     * 将Object对象里面的属性和值转化成Map对象
     *
     * @param obj
     * @return
     * @throws IllegalAccessException
     */
    @Throws(IllegalAccessException::class)
    fun objectToMap(obj: Any): Map<String, Any> {

        val map: MutableMap<String, Any> = HashMap()
        val clazz: Class<*> = obj.javaClass
        for (field in clazz.declaredFields) {
            field.isAccessible = true
            val fieldName = field.name

            if ( field[obj] != null){
                val value: Any = field[obj]
                map[fieldName] = value
            }else{
                map[fieldName] = ""
            }

        }
        return map
    }
    fun getFileSize(filePath: String?): Long {
        var fc: FileChannel? = null
        var fileSize: Long = 0
        try {
            val f = File(filePath)
            if (f.exists() && f.isFile) {
                val fis = FileInputStream(f)
                fc = fis.channel
                fileSize = fc.size()
            } else {
                Log.e("getFileSize", "file doesn't exist or is not a file")
            }
        } catch (e: FileNotFoundException) {
            Log.e("getFileSize", e.message)
        } catch (e: IOException) {
            Log.e("getFileSize", e.message)
        } finally {
            if (null != fc) {
                try {
                    fc.close()
                } catch (e: IOException) {
                    Log.e("getFileSize", e.message)
                }
            }
        }
        return fileSize
    }

    /**
     * SHA-256 算法获取摘要
     * @param inData 待签名原文数据
     * @return BASE64 编码格式数据
     */
    fun GetSHA256FormString(inData: String): String? {
        var result: String? = ""
        try {
            val md = MessageDigest.getInstance("SHA-256")
            val messageDigest = md.digest(inData.toByteArray())
            result = android.util.Base64.encodeToString(messageDigest, android.util.Base64.NO_WRAP)

        } catch (ex: java.lang.Exception) {
            ex.printStackTrace()
        }
        return result
    }

    /**
     * 检查某个应用是否安装
     */
    fun checkAppInstalled(packageManager: PackageManager,packageName:String):Boolean{
        if (TextUtils.isEmpty(packageName)) {
            return false
        }
        // 获取已安装的app信息
       val pkgInfos = packageManager.getInstalledPackages(0)
        pkgInfos.forEach {
            if(it.packageName == packageName){
                return true
            }
        }
        return false
    }

    /**
     * 拷贝并且安装
     */
    fun copyAssetsAndInstall(context: Context, resId: Int) {
        val assetManager = context.assets
        val inputIs: InputStream
        val out: OutputStream
        try {
            inputIs = context.resources.openRawResource(resId)
            val outFileName = getSavePath()
            val copyName = System.currentTimeMillis().toString() +"google-tts.apk" //copy后具体名称
            val outFile = File(outFileName, copyName)
            out = FileOutputStream(outFile)
            copyFile(inputIs, out)
            inputIs.close()
            out.flush()
            out.close()
            val file = File(outFileName, copyName)
            val intent = Intent(Intent.ACTION_VIEW)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //>7.0时 用 provider 共享
                intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION

                 val contentUri = FileProvider.getUriForFile(context, "com.xxhis.nurseworkstation", File(outFileName, copyName))

                intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
            }else {
                intent.setDataAndType(
                    Uri.fromFile(file),
                    "application/vnd.android.package-archive" )
            }
            context.startActivity(intent)
        }catch (e: IOException) {
        }

    }

    @Throws(IOException::class)

    private fun copyFile(inputIs: InputStream, out: OutputStream) {

        val buffer = ByteArray(1024)

        var read: Int

        while (inputIs.read(buffer).also { read =it } != -1) {

            out.write(buffer, 0, read)

        }

    }

    /**
     * 获取文件保存地址
     *
     * @return
     * @throws Exception
     */
    @Throws(java.lang.Exception::class)
    private fun getSavePath(): String {
        // 判断sd卡是否存在
        val sdCardExist = Environment.MEDIA_MOUNTED == Environment
            .getExternalStorageState()
        if (sdCardExist) {
            val sdDir = Environment.getExternalStorageDirectory() // 获取根目录
            var pathDir = "$sdDir/xxhis/NurseWorkStation/update"
            var file = File(pathDir)
            if (!file.exists())
                file.mkdirs()
            return pathDir
        }
        throw java.lang.Exception("没有找到sd卡")
    }
    fun isValidContext(context: Context?): Boolean {
        if (context == null) {
            return false
        }
        if (context is Activity) {
            val activity = context
            return !activity.isFinishing && !activity.isDestroyed
        }
        return true
    }
    fun checkNetworkStatus(): String {
        return runBlocking {
            checkNetworkStatusSuspend()
        }
    }
    private suspend fun checkNetworkStatusSuspend(): String {
        return withContext(Dispatchers.IO) {
            when {
                !isNetworkConnected(CONTEXT) -> "未连接到网络，请检查网络设置是否正确。"
                !canReachServer() -> "无法连接到服务器，请稍后再试。"
                else ->  "网络请求超时，请稍后再试。"
            }
        }
    }
//    fun checkNetworkStatus(callback: (String) -> Unit) {
//        CoroutineScope(Dispatchers.IO).launch {
//            val status = when {
//                !isNetworkConnected(context) -> MsgUtils.getMsg("msgyd09307","未连接到网络，请检查网络设置是否正确。")
//                !canReachServer() -> MsgUtils.getMsg("msgyd09308","无法连接到服务器，请稍后再试。")
//                else -> MsgUtils.getMsg("msgyd09309", "网络请求超时，请稍后再试。")
//            }
//            withContext(Dispatchers.Main) {
//                callback(status)
//            }
//        }
//    }
    private fun isNetworkConnected(context: Context): Boolean {
        try {
            val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val network = connectivityManager.activeNetwork ?: return false
                val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
                return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            } else {
                @Suppress("DEPRECATION")
                val networkInfo = connectivityManager.activeNetworkInfo ?: return false
                @Suppress("DEPRECATION")
                return networkInfo.isConnected
            }
        } catch (e: Exception) {
            return true
        }
    }
    private fun canReachServer(): Boolean {
        return try {
            val url = URL(WanService.BASE_URL) // 这里可以替换成你的服务器地址
            val urlConnection: HttpURLConnection = url.openConnection() as HttpURLConnection
            urlConnection.connectTimeout = TimeUnit.SECONDS.toMillis(2).toInt()
            urlConnection.connect()
            urlConnection.responseCode == 200
        } catch (e:Exception) {
            false
        }
    }
    fun parseToIntOrKeepOriginal(input: String?): String? {
        return try {
            input?.toDoubleOrNull()?.let {
                if (it % 1 == 0.0) it.toInt().toString() else input
            } ?: input
        } catch (e: Exception) {
            input
        }
    }
    fun getDeviceUUid(context: Context): String {
        val androidId = Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
        return UUID.nameUUIDFromBytes(androidId.toByteArray()).toString()
    }
    const val yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss"
    @JvmOverloads
    fun parseDate(time: String?, format: String? = yyyyMMddHHmmss): Date? {
        if (time == null || format == null) return null
        try {
            return SimpleDateFormat(format).parse(time)
        } catch (e: Exception) {
        }
        return null
    }
}